﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Common.Reflect
{
    public static class CreateDelegate<MT, T>
    {
        private static Dictionary<PropertyInfo, Action<MT, T>> dicSet = new Dictionary<PropertyInfo, Action<MT, T>>();
        private static Dictionary<PropertyInfo, Func<MT, T>> dicGet = new Dictionary<PropertyInfo, Func<MT, T>>();
        private static Action<T> staticAct;
        private static Func<T> staticFun;
        private static object lockSet = new object();
        private static object lockGet = new object();

        /// <summary>
        /// 获取属性的Set方法
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Action<MT, T> GetSetAction(PropertyInfo p)
        {
            if (p == null)
                throw new ArgumentNullException("PropertyInfo");
            if (p.CanWrite == false)
                throw new NotSupportedException("属性不支持写操作。");

            Action<MT, T> fun;
            if (dicSet.ContainsKey(p))
            {
                fun = dicSet[p];
            }
            else
            {
                lock (lockSet)
                {
                    if (dicSet.ContainsKey(p))
                    {
                        fun = dicSet[p];
                    }
                    else
                    {
                        MethodInfo getMethod = p.GetSetMethod(true);
                        if (getMethod.IsStatic)
                        {
                            staticAct = (Action<T>)Delegate.CreateDelegate(typeof(Action<string>), getMethod);//先创建为静态委托
                            fun = (Action<MT, T>)Delegate.CreateDelegate(typeof(Action<MT, T>), new Action<MT, T>((m, t) => staticAct.Invoke(t)).Method);
                        }
                        else
                            fun = (Action<MT, T>)Delegate.CreateDelegate(typeof(Action<MT, T>), getMethod);
                        dicSet.Add(p, fun);
                    }
                }
            }
            return fun;
        }
        /// <summary>
        /// 获取属性的Get方法
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static Func<MT, T> GetGetAction(PropertyInfo p)
        {
            if (p == null)
                throw new ArgumentNullException("PropertyInfo");
            if (p.CanRead == false)
                throw new NotSupportedException("属性不支持读操作。");

            Func<MT, T> fun;
            if (dicGet.ContainsKey(p))
            {
                fun = dicGet[p];
            }
            else
            {
                lock (lockGet)
                {
                    if (dicGet.ContainsKey(p))
                    {
                        fun = dicGet[p];
                    }
                    else
                    {
                        MethodInfo getMethod = p.GetGetMethod(true);
                        if (getMethod.IsStatic)
                        {
                            staticFun = (Func<T>)Delegate.CreateDelegate(typeof(Func<string>), getMethod);//先创建为静态委托
                            fun = (Func<MT, T>)Delegate.CreateDelegate(typeof(Func<MT, T>), new Func<MT, T>((m) => staticFun.Invoke()).Method);
                        }
                        else
                            fun = (Func<MT, T>)Delegate.CreateDelegate(typeof(Func<MT, T>), getMethod);
                        dicGet.Add(p, fun);
                    }
                }
            }
            return fun;
        }
    }
}
